package com.rename.wechat.weixin.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.ArrayUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.rename.wechat.weixin.message.resp.Article;
import com.rename.wechat.weixin.message.resp.ImageMessage;
import com.rename.wechat.weixin.message.resp.MusicMessage;
import com.rename.wechat.weixin.message.resp.NewsMessage;
import com.rename.wechat.weixin.message.resp.TextMessage;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDomDriver;

/**
 * 消息工具类
 * @author Bruce
 *
 */
public class MessageUtil {
	
	//===================================消息接收与回复===================================
	// 接收类型：文本消息
	public static final String REQ_MESSAGE_TYPE_TEXT = "text";
	// 接收类型：图片消息
	public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
	// 接收类型：语音消息
	public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
	// 接收类型：视频消息
	public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
	// 接收类型：小视频消息
	public static final String REQ_MESSAGE_TYPE_SHORTVIDEO = "shortvideo";
	// 接收类型：地理位置消息
	public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
	// 接收类型：链接消息
	public static final String REQ_MESSAGE_TYPE_LINK = "link";
	
	// 回复类型：文本消息
	public static final String RESP_MESSAGE_TYPE_TEXT = "text";
	// 回复类型：图片消息
	public static final String RESP_MESSAGE_TYPE_IMAGE = "image";
	// 回复类型：语音消息
	public static final String RESP_MESSAGE_TYPE_VOICE = "voice";
	// 回复类型：视频消息
	public static final String RESP_MESSAGE_TYPE_VIDEO = "video";
	// 回复类型：音乐消息
	public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
	// 回复类型：图文消息
	public static final String RESP_MESSAGE_TYPE_NEWS = "news";
	//===================================消息接收与回复===================================
	
	//===================================用户关注/取关事件推送===================================
	// 用户关注事件推送：subscribe
	public static final String REQ_MESSAGE_EVENT_SUBSCRIBE = "subscribe";
	// 用户取消关注事件推送：unsubscribe
	public static final String REQ_MESSAGE_EVENT_UNSUBSCRIBE = "unsubscribe";
	//===================================用户关注/取关事件推送===================================
	
	//===================================自定义菜单事件推送===================================
	// 接收类型：自定义菜单事件推送
	public static final String REQ_MESSAGE_TYPE_EVENT = "event";
	
	// 接收事件：click
	public static final String REQ_MESSAGE_EVENT_CLICK = "CLICK";
	// 接收事件：view
	public static final String REQ_MESSAGE_EVENT_VIEW = "VIEW";
	// 接收事件：scancode_push
	public static final String REQ_MESSAGE_EVENT_SCANCODE_PUSH = "scancode_push";
	// 接收事件：scancode_waitmsg
	public static final String REQ_MESSAGE_EVENT_SCANCODE_WAITMSG = "scancode_waitmsg";
	// 接收事件：pic_sysphoto
	public static final String REQ_MESSAGE_EVENT_PIC_SYSPHOTO = "pic_sysphoto";
	// 接收事件：pic_photo_or_album
	public static final String REQ_MESSAGE_EVENT_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album";
	// 接收事件：pic_weixin
	public static final String REQ_MESSAGE_EVENT_PIC_WEIXIN = "pic_weixin";
	// 接收事件：location_select
	public static final String REQ_MESSAGE_EVENT_LOCATION_SELECT = "location_select";
	//===================================自定义菜单事件推送===================================
	
	private static XStream xStream = new XStream(new XppDomDriver(){
		public HierarchicalStreamWriter createWriter(Writer out) {

			return new PrettyPrintWriter(out) {

				// 对所有xml节点的转换都增加CDATA标记
				boolean cdata = true;

				@SuppressWarnings("rawtypes")
				public void startNode(String name, Class calzz) {

					// 如果节点是时间节点/图文消息数量节点就不要添加CDATA标记
					if ("CreateTime".equals(name) || "ArticleCount".equals(name)) {
						cdata = false;
					} else{
						cdata = true;
					}

					super.startNode(name, calzz);
				}

				protected void writeText(QuickWriter quickWriter, String text) {
					if (cdata) {
						quickWriter.write("<![CDATA[");
						quickWriter.write(text);
						quickWriter.write("]]>");
						//System.out.println("<![CDATA[" + text + "]]>");
					} else {
						quickWriter.write(text);
						//System.out.println(text);
					}
				}
			};
		}
	});
	
	/**
	 * xml转为map
	 * @param request
	 * @return
	 * @throws IOException
	 * @throws DocumentException
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException{
		
		// 解析结果存放在Map中
		Map<String, String> map = new HashMap<String, String>();
		// xml解析器
		SAXReader saxReader = new SAXReader();
		// 从request中读取输入流
		InputStream inputStream = request.getInputStream();
		// 将输入流转为document
		Document document = saxReader.read(inputStream);
		
		// 获取根节点
		Element root = document.getRootElement();
		// 获取所有子节点
		List<Element> elements = root.elements();
		
		// 遍历子节点
		for(Element element : elements){
			map.put(element.getName(), element.getText());
		}
		
		// 关闭输入流
		inputStream.close();
		inputStream = null;
		
		return map;
	}
	
	/**
	 * 文本消息转为xml
	 * @param textMessage
	 * @return
	 */
	public static String textMessageToXml(TextMessage textMessage){
		xStream.alias("xml", textMessage.getClass());
		return xStream.toXML(textMessage);
	}
	
	/**
	 * 音乐消息转为xml
	 * @param musicMessage
	 * @return
	 */
	public static String musicMessageToXml(MusicMessage musicMessage){
		xStream.alias("xml", musicMessage.getClass());
		return xStream.toXML(musicMessage);
	}
	
	/**
	 * 图片消息转为xml
	 * @param imageMessage
	 * @return
	 */
	public static String imageMessageToXml(ImageMessage imageMessage){
		xStream.alias("xml", imageMessage.getClass());
		return xStream.toXML(imageMessage);
	}
	
	/**
	 * 图文消息转为xml
	 * @param newsMessage
	 * @return
	 */
	public static String newsMessageToXml(NewsMessage newsMessage){
		xStream.alias("xml", newsMessage.getClass());
		xStream.alias("item", (new Article()).getClass());
		return xStream.toXML(newsMessage);
	}
	
//	/**
//	 * 将成员变量在xml文件中的别名的首字母改为大写
//	 * @param clazz
//	 */
//	@SuppressWarnings("rawtypes")
//	private static void aliasField2UpperCase(Class clazz){
//		// 获取当前类所有成员变量
//		Field[] fields = clazz.getDeclaredFields();
//		// 获取当前类父类所有成员变量
//		Class superClazz = clazz.getSuperclass();
//		Field[] superFields = superClazz.getDeclaredFields();
//		// 合并当前类和其父类的所有成员变量
//		Field[] allFields = ArrayUtils.addAll(fields, superFields);
//		
//		for(int i = 0; i < allFields.length; i++){
//			// 将成员变量在xml文件中的别名的首字母改为大写
//			String fieldName = allFields[i].getName();
//			String alias = fieldName.replace(fieldName.charAt(0), Character.toUpperCase(fieldName.charAt(0)));
//			xStream.aliasField(alias, clazz, fieldName);
//		}
//	}

}
